use serde::{Deserialize, Serialize};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::RwLock;
use tokio::time::sleep;
use thiserror::Error;
use tauri::{AppHandle, Emitter};

// EZK SIP library imports
use sip_core::Endpoint;
use sip_core::transport::udp::Udp;
use sip_core::transport::tcp::TcpListener;
use sip_core::transport::streaming::StreamingListenerBuilder;
use sip_ua::{dialog::DialogLayer, invite::InviteLayer, RegistrarConfig, Registration, RegisterError};
use sip_auth::{DigestAuthenticator, DigestCredentials, DigestUser};
use sip_types::uri::SipUri;

#[derive(Debug, Error)]
pub enum SipManagerError {
    #[error("Registration failed: {0}")]
    RegistrationFailed(String),
    #[error("Authentication failed: {0}")]
    AuthenticationFailed(String),
    #[error("Network error: {0}")]
    NetworkError(String),
    #[error("Configuration error: {0}")]
    ConfigError(String),
    #[error("Transport error: {0}")]
    TransportError(String),
    #[error("Connection test failed: {0}")]
    ConnectionTestFailed(String),
    #[error("Invalid URI: {0}")]
    InvalidUri(String),
    #[error("Server unreachable: {0}")]
    ServerUnreachable(String),
    #[error("Timeout error: {0}")]
    TimeoutError(String),
    #[error("Invalid credentials: {0}")]
    InvalidCredentials(String),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SipConfig {
    pub server: String,
    pub port: u16,
    pub username: String,
    pub password: String,
    pub transport: TransportType,
    pub display_name: Option<String>,
    pub local_port: Option<u16>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum TransportType {
    UDP,
    TCP,
    TLS,
    Auto,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum RegistrationStatus {
    Unregistered,
    Registering,
    Registered,
    Failed(String),
    AuthenticationFailed(String),
    NetworkError(String),
    TimeoutError(String),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegistrationEvent {
    pub status: RegistrationStatus,
    pub message: Option<String>,
    pub retry_count: Option<u32>,
    pub next_retry_in: Option<u64>, // seconds
    pub error_code: Option<String>,
    pub server_response: Option<String>,
    pub timestamp: u64, // Unix timestamp
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectionTestResult {
    pub success: bool,
    pub transport_used: TransportType,
    pub response_time: Option<u64>,
    pub error_message: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkStatus {
    pub is_connected: bool,
    pub active_transport: Option<TransportType>,
    pub local_address: Option<String>,
    pub server_address: Option<String>,
}

pub struct SipManager {
    config: Arc<RwLock<Option<SipConfig>>>,
    status: Arc<RwLock<RegistrationStatus>>,
    endpoint: Arc<RwLock<Option<Endpoint>>>,
    registration: Arc<RwLock<Option<Registration>>>,
    network_status: Arc<RwLock<NetworkStatus>>,
    app_handle: Arc<RwLock<Option<AppHandle>>>,
    retry_count: Arc<RwLock<u32>>,
    max_retries: u32,
    retry_delay_base: Duration,
    last_error: Arc<RwLock<Option<String>>>,
    auth_failure_count: Arc<RwLock<u32>>,
    max_auth_failures: u32,
}

impl SipManager {
    pub fn new() -> Self {
        Self {
            config: Arc::new(RwLock::new(None)),
            status: Arc::new(RwLock::new(RegistrationStatus::Unregistered)),
            endpoint: Arc::new(RwLock::new(None)),
            registration: Arc::new(RwLock::new(None)),
            network_status: Arc::new(RwLock::new(NetworkStatus {
                is_connected: false,
                active_transport: None,
                local_address: None,
                server_address: None,
            })),
            app_handle: Arc::new(RwLock::new(None)),
            retry_count: Arc::new(RwLock::new(0)),
            max_retries: 3,
            retry_delay_base: Duration::from_secs(2),
            last_error: Arc::new(RwLock::new(None)),
            auth_failure_count: Arc::new(RwLock::new(0)),
            max_auth_failures: 3,
        }
    }

    pub async fn set_app_handle(&self, app_handle: AppHandle) {
        *self.app_handle.write().await = Some(app_handle);
    }

    pub async fn login(&self, config: SipConfig) -> Result<(), SipManagerError> {
        // Validate configuration
        self.validate_config(&config)?;
        
        // Store configuration and reset counters
        *self.config.write().await = Some(config.clone());
        *self.retry_count.write().await = 0;
        *self.auth_failure_count.write().await = 0;
        *self.last_error.write().await = None;
        
        log::info!("Starting login process for user: {} at server: {}:{}", 
                   config.username, config.server, config.port);
        
        self.attempt_login_with_retry(config).await
    }

    fn validate_config(&self, config: &SipConfig) -> Result<(), SipManagerError> {
        if config.server.is_empty() {
            return Err(SipManagerError::ConfigError("Server address cannot be empty".to_string()));
        }
        if config.username.is_empty() {
            return Err(SipManagerError::ConfigError("Username cannot be empty".to_string()));
        }
        if config.password.is_empty() {
            return Err(SipManagerError::ConfigError("Password cannot be empty".to_string()));
        }
        if config.port == 0 || config.port > 65535 {
            return Err(SipManagerError::ConfigError("Invalid port number".to_string()));
        }
        Ok(())
    }

    async fn attempt_login_with_retry(&self, config: SipConfig) -> Result<(), SipManagerError> {
        let mut current_retry = 0;
        
        loop {
            // Update status and notify frontend
            *self.status.write().await = RegistrationStatus::Registering;
            self.emit_registration_event(RegistrationEvent {
                status: RegistrationStatus::Registering,
                message: if current_retry > 0 {
                    Some(format!("Retrying registration (attempt {} of {})", current_retry + 1, self.max_retries + 1))
                } else {
                    Some("Attempting to register with SIP server".to_string())
                },
                retry_count: Some(current_retry),
                next_retry_in: None,
                error_code: None,
                server_response: None,
                timestamp: std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .unwrap_or_default()
                    .as_secs(),
            }).await;

            log::info!("Attempting to register with server: {}:{} via {:?} (attempt {} of {})", 
                       config.server, config.port, config.transport, current_retry + 1, self.max_retries + 1);

            // Create endpoint with appropriate transport
            match self.create_endpoint(&config).await {
                Ok(endpoint) => {
                    *self.endpoint.write().await = Some(endpoint.clone());

                    // Update network status
                    {
                        let mut network_status = self.network_status.write().await;
                        network_status.is_connected = true;
                        network_status.active_transport = Some(config.transport.clone());
                        network_status.server_address = Some(format!("{}:{}", config.server, config.port));
                    }

                    // Perform SIP registration
                    match self.perform_registration(&config, endpoint).await {
                        Ok(registration) => {
                            *self.registration.write().await = Some(registration);
                            *self.status.write().await = RegistrationStatus::Registered;
                            *self.retry_count.write().await = 0;
                            *self.auth_failure_count.write().await = 0;
                            *self.last_error.write().await = None;
                            
                            log::info!("Successfully registered with SIP server");
                            
                            // Emit success event
                            self.emit_registration_event(RegistrationEvent {
                                status: RegistrationStatus::Registered,
                                message: Some("Successfully registered with SIP server".to_string()),
                                retry_count: Some(current_retry),
                                next_retry_in: None,
                                error_code: None,
                                server_response: None,
                                timestamp: std::time::SystemTime::now()
                                    .duration_since(std::time::UNIX_EPOCH)
                                    .unwrap_or_default()
                                    .as_secs(),
                            }).await;
                            
                            return Ok(());
                        }
                        Err(e) => {
                            log::error!("Registration failed: {}", e);
                            *self.last_error.write().await = Some(e.to_string());
                            
                            // Check if this is an authentication failure
                            let is_auth_failure = self.is_authentication_error(&e);
                            if is_auth_failure {
                                let mut auth_failures = self.auth_failure_count.write().await;
                                *auth_failures += 1;
                                
                                if *auth_failures >= self.max_auth_failures {
                                    let error_msg = "Authentication failed: Invalid credentials".to_string();
                                    *self.status.write().await = RegistrationStatus::AuthenticationFailed(error_msg.clone());
                                    self.cleanup_connection().await;
                                    
                                    self.emit_registration_event(RegistrationEvent {
                                        status: RegistrationStatus::AuthenticationFailed(error_msg.clone()),
                                        message: Some("Authentication failed: Please check your username and password".to_string()),
                                        retry_count: Some(current_retry),
                                        next_retry_in: None,
                                        error_code: Some("401".to_string()),
                                        server_response: Some(e.to_string()),
                                        timestamp: std::time::SystemTime::now()
                                            .duration_since(std::time::UNIX_EPOCH)
                                            .unwrap_or_default()
                                            .as_secs(),
                                    }).await;
                                    
                                    return Err(SipManagerError::AuthenticationFailed(error_msg));
                                }
                            }
                            
                            if current_retry >= self.max_retries {
                                // Max retries reached, fail permanently
                                let error_msg = format!("Registration failed after {} attempts: {}", current_retry + 1, e);
                                let status = if is_auth_failure {
                                    RegistrationStatus::AuthenticationFailed(error_msg.clone())
                                } else if self.is_network_error(&e) {
                                    RegistrationStatus::NetworkError(error_msg.clone())
                                } else if self.is_timeout_error(&e) {
                                    RegistrationStatus::TimeoutError(error_msg.clone())
                                } else {
                                    RegistrationStatus::Failed(error_msg.clone())
                                };
                                
                                *self.status.write().await = status.clone();
                                self.cleanup_connection().await;
                                
                                self.emit_registration_event(RegistrationEvent {
                                    status,
                                    message: Some(error_msg.clone()),
                                    retry_count: Some(current_retry),
                                    next_retry_in: None,
                                    error_code: self.extract_error_code(&e),
                                    server_response: Some(e.to_string()),
                                    timestamp: std::time::SystemTime::now()
                                        .duration_since(std::time::UNIX_EPOCH)
                                        .unwrap_or_default()
                                        .as_secs(),
                                }).await;
                                
                                return Err(SipManagerError::RegistrationFailed(error_msg));
                            } else {
                                // Calculate retry delay with exponential backoff
                                let retry_delay = self.retry_delay_base * (2_u32.pow(current_retry));
                                let retry_delay_secs = retry_delay.as_secs();
                                
                                log::info!("Registration failed, retrying in {} seconds", retry_delay_secs);
                                
                                // Emit retry event
                                let status = if is_auth_failure {
                                    RegistrationStatus::AuthenticationFailed(format!("Authentication failed: {}", e))
                                } else if self.is_network_error(&e) {
                                    RegistrationStatus::NetworkError(format!("Network error: {}", e))
                                } else if self.is_timeout_error(&e) {
                                    RegistrationStatus::TimeoutError(format!("Timeout error: {}", e))
                                } else {
                                    RegistrationStatus::Failed(format!("Registration failed: {}", e))
                                };
                                
                                self.emit_registration_event(RegistrationEvent {
                                    status,
                                    message: Some(format!("Registration failed, retrying in {} seconds", retry_delay_secs)),
                                    retry_count: Some(current_retry),
                                    next_retry_in: Some(retry_delay_secs),
                                    error_code: self.extract_error_code(&e),
                                    server_response: Some(e.to_string()),
                                    timestamp: std::time::SystemTime::now()
                                        .duration_since(std::time::UNIX_EPOCH)
                                        .unwrap_or_default()
                                        .as_secs(),
                                }).await;
                                
                                // Wait before retry
                                sleep(retry_delay).await;
                                current_retry += 1;
                                *self.retry_count.write().await = current_retry;
                            }
                        }
                    }
                }
                Err(e) => {
                    log::error!("Failed to create endpoint: {}", e);
                    
                    if current_retry >= self.max_retries {
                        let error_msg = format!("Failed to create endpoint after {} attempts: {}", current_retry + 1, e);
                        *self.status.write().await = RegistrationStatus::Failed(error_msg.clone());
                        self.cleanup_connection().await;
                        
                        self.emit_registration_event(RegistrationEvent {
                            status: RegistrationStatus::Failed(error_msg.clone()),
                            message: Some(error_msg.clone()),
                            retry_count: Some(current_retry),
                            next_retry_in: None,
                            error_code: None,
                            server_response: Some(e.to_string()),
                            timestamp: std::time::SystemTime::now()
                                .duration_since(std::time::UNIX_EPOCH)
                                .unwrap_or_default()
                                .as_secs(),
                        }).await;
                        
                        return Err(e);
                    } else {
                        let retry_delay = self.retry_delay_base * (2_u32.pow(current_retry));
                        let retry_delay_secs = retry_delay.as_secs();
                        
                        log::info!("Endpoint creation failed, retrying in {} seconds", retry_delay_secs);
                        
                        self.emit_registration_event(RegistrationEvent {
                            status: RegistrationStatus::Failed(format!("Endpoint creation failed: {}", e)),
                            message: Some(format!("Endpoint creation failed, retrying in {} seconds", retry_delay_secs)),
                            retry_count: Some(current_retry),
                            next_retry_in: Some(retry_delay_secs),
                            error_code: None,
                            server_response: Some(e.to_string()),
                            timestamp: std::time::SystemTime::now()
                                .duration_since(std::time::UNIX_EPOCH)
                                .unwrap_or_default()
                                .as_secs(),
                        }).await;
                        
                        sleep(retry_delay).await;
                        current_retry += 1;
                        *self.retry_count.write().await = current_retry;
                    }
                }
            }
        }
    }

    pub async fn logout(&self) -> Result<(), SipManagerError> {
        log::info!("Logging out and unregistering from SIP server");
        
        // Drop registration (this will automatically unregister)
        *self.registration.write().await = None;
        
        // Cleanup connection
        self.cleanup_connection().await;
        
        // Reset all state
        *self.status.write().await = RegistrationStatus::Unregistered;
        *self.config.write().await = None;
        *self.retry_count.write().await = 0;
        *self.auth_failure_count.write().await = 0;
        *self.last_error.write().await = None;
        
        // Emit logout event
        self.emit_registration_event(RegistrationEvent {
            status: RegistrationStatus::Unregistered,
            message: Some("Successfully logged out".to_string()),
            retry_count: None,
            next_retry_in: None,
            error_code: None,
            server_response: None,
            timestamp: std::time::SystemTime::now()
                .duration_since(std::time::UNIX_EPOCH)
                .unwrap_or_default()
                .as_secs(),
        }).await;
        
        log::info!("Successfully logged out");
        Ok(())
    }

    pub async fn get_registration_status(&self) -> RegistrationStatus {
        self.status.read().await.clone()
    }

    pub async fn test_connection(&self, server: String, port: u16, transport: TransportType) -> Result<ConnectionTestResult, SipManagerError> {
        log::info!("Testing connection to {}:{} via {:?}", server, port, transport);
        
        let _start_time = Instant::now();
        
        // Test connection based on transport type
        match transport {
            TransportType::Auto => {
                // Try UDP first, then TCP if UDP fails
                match self.test_transport_connection(&server, port, TransportType::UDP).await {
                    Ok(result) => Ok(result),
                    Err(_) => {
                        log::info!("UDP connection failed, trying TCP");
                        self.test_transport_connection(&server, port, TransportType::TCP).await
                    }
                }
            }
            _ => self.test_transport_connection(&server, port, transport).await
        }
    }

    pub async fn get_network_status(&self) -> NetworkStatus {
        self.network_status.read().await.clone()
    }

    pub fn get_endpoint(&self) -> Arc<RwLock<Option<Endpoint>>> {
        self.endpoint.clone()
    }

    pub async fn get_retry_count(&self) -> u32 {
        *self.retry_count.read().await
    }

    pub fn get_max_retries(&self) -> u32 {
        self.max_retries
    }

    pub async fn force_retry_registration(&self) -> Result<(), SipManagerError> {
        if let Some(config) = self.config.read().await.clone() {
            log::info!("Force retrying registration");
            // Reset retry counters for forced retry
            *self.retry_count.write().await = 0;
            *self.auth_failure_count.write().await = 0;
            *self.last_error.write().await = None;
            
            self.attempt_login_with_retry(config).await
        } else {
            Err(SipManagerError::ConfigError("No configuration available for retry".to_string()))
        }
    }

    pub async fn get_last_error(&self) -> Option<String> {
        self.last_error.read().await.clone()
    }

    pub async fn get_auth_failure_count(&self) -> u32 {
        *self.auth_failure_count.read().await
    }

    pub fn get_max_auth_failures(&self) -> u32 {
        self.max_auth_failures
    }

    pub async fn reset_auth_failures(&self) {
        *self.auth_failure_count.write().await = 0;
        log::info!("Authentication failure count reset");
    }

    pub async fn is_authentication_locked(&self) -> bool {
        *self.auth_failure_count.read().await >= self.max_auth_failures
    }

    async fn emit_registration_event(&self, event: RegistrationEvent) {
        if let Some(app_handle) = self.app_handle.read().await.as_ref() {
            if let Err(e) = app_handle.emit("registration-event", &event) {
                log::error!("Failed to emit registration event: {}", e);
            }
        }
    }

    // Private helper methods
    async fn create_endpoint(&self, config: &SipConfig) -> Result<Endpoint, SipManagerError> {
        let mut builder = Endpoint::builder();
        
        // Determine local bind address
        let local_port = config.local_port.unwrap_or(0); // 0 means any available port
        let bind_addr = format!("0.0.0.0:{}", local_port);
        
        // Add transport layer based on configuration
        match config.transport {
            TransportType::UDP => {
                Udp::spawn(&mut builder, &bind_addr)
                    .await
                    .map_err(|e| SipManagerError::TransportError(format!("UDP transport failed: {}", e)))?;
            }
            TransportType::TCP => {
                TcpListener::new().spawn(&mut builder, &bind_addr)
                    .await
                    .map_err(|e| SipManagerError::TransportError(format!("TCP transport failed: {}", e)))?;
            }
            TransportType::TLS => {
                // For TLS, we'll use TCP as the base transport for now
                // In a production implementation, you would configure proper TLS
                log::warn!("TLS transport requested but using TCP as fallback");
                TcpListener::new().spawn(&mut builder, &bind_addr)
                    .await
                    .map_err(|e| SipManagerError::TransportError(format!("TLS transport failed: {}", e)))?;
            }
            TransportType::Auto => {
                // For Auto mode, start with UDP and add TCP as fallback
                match Udp::spawn(&mut builder, &bind_addr).await {
                    Ok(_) => {
                        log::info!("UDP transport initialized successfully");
                    }
                    Err(e) => {
                        log::warn!("UDP transport failed, trying TCP: {}", e);
                        TcpListener::new().spawn(&mut builder, &bind_addr)
                            .await
                            .map_err(|e| SipManagerError::TransportError(format!("Auto transport failed (both UDP and TCP): {}", e)))?;
                    }
                }
            }
        }

        // Add required SIP layers
        builder.add_layer(DialogLayer::default());
        builder.add_layer(InviteLayer::default());

        let endpoint = builder.build();
        
        // Update network status (local address will be set when transport is created)
        let mut network_status = self.network_status.write().await;
        network_status.local_address = Some(format!("0.0.0.0:{}", local_port));

        Ok(endpoint)
    }

    async fn perform_registration(&self, config: &SipConfig, endpoint: Endpoint) -> Result<Registration, RegisterError<sip_auth::DigestError>> {
        // Parse server URI
        let server_uri = format!("sip:{}", config.server);
        let registrar_uri: SipUri = server_uri.parse()
            .map_err(|e| RegisterError::Core(sip_core::Error::from(std::io::Error::other(format!("Invalid server URI: {}", e)))))?;

        // Create registrar config
        let registrar_config = RegistrarConfig::new(
            config.username.clone().into(),
            registrar_uri,
        );

        // Create credentials
        let mut credentials = DigestCredentials::new();
        credentials.add_for_realm(
            &config.server,
            DigestUser::new(&config.username, config.password.as_bytes()),
        );

        // Perform registration
        Registration::register(
            endpoint,
            registrar_config,
            DigestAuthenticator::new(credentials),
        ).await
    }

    async fn test_transport_connection(&self, server: &str, port: u16, transport: TransportType) -> Result<ConnectionTestResult, SipManagerError> {
        let start_time = Instant::now();
        
        // Create a temporary endpoint for testing
        let mut builder = Endpoint::builder();
        let bind_addr = "0.0.0.0:0"; // Use any available port for testing
        
        let transport_result = match transport {
            TransportType::UDP => {
                Udp::spawn(&mut builder, bind_addr).await.map(|_| ())
            }
            TransportType::TCP => {
                TcpListener::new().spawn(&mut builder, bind_addr).await
            }
            TransportType::TLS => {
                // For TLS, we'll use TCP as the base transport for now
                log::warn!("TLS transport requested but using TCP as fallback for connection test");
                TcpListener::new().spawn(&mut builder, bind_addr).await
            }
            TransportType::Auto => {
                // This shouldn't be called directly, but handle it anyway
                Udp::spawn(&mut builder, bind_addr).await.map(|_| ())
            }
        };

        match transport_result {
            Ok(_) => {
                let _endpoint = builder.build();
                let response_time = start_time.elapsed().as_millis() as u64;
                
                // Test basic connectivity by trying to create the endpoint
                // In a real implementation, you might send an OPTIONS request
                log::info!("Connection test successful for {}:{} via {:?} ({}ms)", 
                          server, port, transport, response_time);
                
                Ok(ConnectionTestResult {
                    success: true,
                    transport_used: transport,
                    response_time: Some(response_time),
                    error_message: None,
                })
            }
            Err(e) => {
                let error_msg = format!("Transport connection failed: {}", e);
                log::error!("{}", error_msg);
                
                Ok(ConnectionTestResult {
                    success: false,
                    transport_used: transport,
                    response_time: None,
                    error_message: Some(error_msg),
                })
            }
        }
    }

    async fn cleanup_connection(&self) {
        *self.endpoint.write().await = None;
        
        let mut network_status = self.network_status.write().await;
        network_status.is_connected = false;
        network_status.active_transport = None;
        network_status.local_address = None;
        network_status.server_address = None;
    }

    fn is_authentication_error(&self, error: &RegisterError<sip_auth::DigestError>) -> bool {
        // Check if the error indicates authentication failure
        match error {
            RegisterError::Auth(_) => true,
            RegisterError::Failed(status_code) => {
                // Check for 401 Unauthorized or 403 Forbidden status codes
                let code_str = format!("{:?}", status_code);
                code_str.contains("401") || code_str.contains("403")
            }
            RegisterError::Core(core_error) => {
                // Check for 401 Unauthorized or 403 Forbidden responses
                let error_str = core_error.to_string().to_lowercase();
                error_str.contains("401") || error_str.contains("unauthorized") ||
                error_str.contains("403") || error_str.contains("forbidden") ||
                error_str.contains("authentication") || error_str.contains("credentials")
            }
        }
    }

    fn is_network_error(&self, error: &RegisterError<sip_auth::DigestError>) -> bool {
        let error_str = error.to_string().to_lowercase();
        error_str.contains("network") || error_str.contains("connection") ||
        error_str.contains("unreachable") || error_str.contains("dns") ||
        error_str.contains("resolve") || error_str.contains("socket")
    }

    fn is_timeout_error(&self, error: &RegisterError<sip_auth::DigestError>) -> bool {
        let error_str = error.to_string().to_lowercase();
        error_str.contains("timeout") || error_str.contains("timed out") ||
        error_str.contains("deadline") || error_str.contains("elapsed")
    }

    fn extract_error_code(&self, error: &RegisterError<sip_auth::DigestError>) -> Option<String> {
        let error_str = error.to_string();
        
        // Try to extract SIP response codes (3-digit numbers)
        if let Some(captures) = regex::Regex::new(r"\b(\d{3})\b").unwrap().captures(&error_str) {
            if let Some(code) = captures.get(1) {
                return Some(code.as_str().to_string());
            }
        }
        
        // Return common error codes based on error type
        if self.is_authentication_error(error) {
            Some("401".to_string())
        } else if self.is_network_error(error) {
            Some("503".to_string())
        } else if self.is_timeout_error(error) {
            Some("408".to_string())
        } else {
            None
        }
    }
}

impl Default for SipManager {
    fn default() -> Self {
        Self::new()
    }
}